using System;
using System.Collections;
using myGA.Genome;

namespace myGA
{
	//public delegate float FitnessFunction(float x);


	public enum SelectionType
	{
		Roulette, Random, Rank, Tournament
	}

	public enum CrossoverType
	{
		SinglePoint, DoublePoint
	}


	/// <summary>
	/// Summary description for Population.
	/// </summary>
	public class Population
	{
		private ArrayList myPop;
		static private int chromID = 0;

		public Population(int popSize)
		{
			myPop = new ArrayList();

			for( int i = 0; i < popSize; i++)
			{
				//Genome1A c = new Genome1A(i);
                BaseGenome c = new Genome1A(i);
				myPop.Add(c);
			}
		}

        public int PopSize
        {
            get { return myPop.Count; }
        }

		public void DoGeneration(float muRate, float selRate)
		{
			ArrayList newPop = new ArrayList();
			
			int selCount = (int) (selRate*myPop.Count);
			
//			Console.Out.WriteLine("selRate: " + selRate + " PopSize: " + myPop.Count
//				+ " selCt: " + selCount);

			for(int i = 0; i < selCount; i++)
			{
				// selection
				//Genome1A parent1 = Selection(0);
				//Genome1A parent2 = Selection(1);
                BaseGenome parent1 = Selection(0);
                BaseGenome parent2 = Selection(1);


				//Genome1A child1 = new Genome1A(chromID++);
				//Genome1A child2 = new Genome1A(chromID++);

                BaseGenome child1 = new Genome1A(chromID++);
                BaseGenome child2 = new Genome1A(chromID++);

				// crossover
				Crossover(parent1, parent2, ref child1, ref child2);

				// mutate
				child1.Mutate(muRate);
				child2.Mutate(muRate);

				// replacement
				newPop.Add(child1);
				newPop.Add(child2);
			}

			myPop.RemoveRange(myPop.Count - newPop.Count ,newPop.Count);
			//myPop.Clear();
			myPop.AddRange(newPop);

		}
	
		//private void Crossover(Genome1A parent1, Genome1A parent2,
			//ref Genome1A child1, ref Genome1A child2)
		
		private void Crossover(BaseGenome parent1, BaseGenome parent2,
			ref BaseGenome child1, ref BaseGenome child2)
        {
			int id1 = child1.MyID;
			int id2 = child2.MyID;

			int index = Genome1A.myRandom.Next(8);

			for(int i = 0; i < index; i++)
			{
                (Genome1A)child1[i] = (Genome1A)parent1[i];
                (Genome1A)child2[i] = (Genome1A)parent2[i];
			}
			for(int i = index; i < 8; i++)
			{
				child1[i] = parent2[i];
				child2[i] = parent1[i];
			}

			child1.MyID = id1;
			child2.MyID = id2;
		}
				
		//private Genome1A Selection(int i)
        private BaseGenome Selection(int i)
		{
			// tournament
			int index1 = Genome1A.myRandom.Next(myPop.Count);
			int index2 = Genome1A.myRandom.Next(myPop.Count);
			
			//Genome1A chrom1 = (Genome1A) myPop[index1];
			//Genome1A chrom2 = (Genome1A) myPop[index2];
            BaseGenome chrom1 = (Genome1A)myPop[index1];
            BaseGenome chrom2 = (Genome1A)myPop[index2];

			if(chrom1.FitnessValue > chrom2.FitnessValue)
				return chrom1;
			else
				return chrom2;
		}

	
		public void Evaluate(FitFunc fitnessFunction)
		{
			for(int i = 0; i < myPop.Count; i++)
			{
				//Genome1A chrom = (Genome1A) myPop[i];
                BaseGenome chrom = (Genome1A)myPop[i];
                double [] val = new double[1];
				val[0] = (int)chrom.IntValue;
				chrom.FitnessValue = fitnessFunction(val);
			}

			myPop.Sort(new Chrom1AComparer() );
		}	


		public void Randomize()
		{
			//			for(int i = 0; i < myPopSize; i++)
			//				myPop[i]
			//		
		}


		public void ClearAll()
		{
		}
		

		// Add
		//public void Add[i]
		
		// Remove
		// public void Remove[i]

		// Replace
		// public void Replace()  ??
		
		//stats
		// worse, best, avg

		
		public void CalculateStats()
		{
		
		}
		

		//public Genome1A GetGenome(int i)
        public BaseGenome GetGenome(int i)
		{
			return (BaseGenome) myPop[i];
		}


		public override string ToString()
		{
			string temp = "Pop: (size) " + myPop.Count + "\n";

			for(int i = 0; i < myPop.Count; i++)
				temp += myPop[i].ToString() + "\n";

			return temp;
		}
		
	}
}
